package com.flextribe.net
{
	import flash.events.ErrorEvent;
	import flash.events.Event;
	import flash.events.EventDispatcher;
	import flash.events.IEventDispatcher;
	import flash.net.ObjectEncoding;
	import flash.net.SharedObject;
	import flash.net.SharedObjectFlushStatus;
	import flash.utils.Proxy;
	import flash.utils.flash_proxy;
	
	use namespace flash_proxy;
	
	public dynamic class LocalStore extends Proxy implements IEventDispatcher
	{
		
		
		public static var ILLEGAL_CHARACTERS:Array = ["~", "%", "&", "\\", ";", ":", "\"", "'", ",", "<", ">", "?", "#", " " ];
		
		private var eventDispatcher:EventDispatcher;
		
		private var _so:SharedObject;
		private var _soModified:Boolean;
		
		private var _sharedObjectName:String;
		private var _localPath:String;
		private var _secure:Boolean;
		private var _autoCommit:Boolean;
		
		public function LocalStore(sharedObjectName:String, localPath:String="/", secure:Boolean=false, autoCommit:Boolean=true){
			_sharedObjectName = sharedObjectName;
			_localPath = localPath;
			_secure = secure;
			_autoCommit = autoCommit;
			
			eventDispatcher = new EventDispatcher(this);
			
			if(_sharedObjectName != "") {
				_so = SharedObject.getLocal(_sharedObjectName, _localPath, _secure);
				_so.objectEncoding = ObjectEncoding.AMF0;
			}
		}
		
		
		public function get so():SharedObject{
			return _so;
		}
		
		public function get soModified():Boolean{
			return _soModified;
		}
		
		public function set soModified(value:Boolean):void{
			_soModified = value;
			if(_autoCommit && _soModified) commitProperties();
		}
		
		public function get autoCommit():Boolean{
			return _autoCommit;
		}
		
		public function set autoCommit(value:Boolean):void{
			_autoCommit = value;
			if(_autoCommit && _soModified) commitProperties();
		}
		
		override flash_proxy function hasProperty(name:*):Boolean {
	        return _so.data[name] != undefined;
	    }
		
		override flash_proxy function getProperty(name:*):* {
	        return _so.data[name] != undefined ? _so.data[name] : null;
	    }
		
		override flash_proxy function setProperty(name:*, value:*):void {
	        _so.data[name] = value;
	        _soModified = true;
			if(_autoCommit) commitProperties();
	    }
		public function clear():void{
			_so.clear();
			var flushResult:Boolean = commitProperties();
			if(flushResult) _so = null;
		} 			
		
		public function commitProperties():Boolean{
			var r:String = _so.flush();
			switch(r){
				case SharedObjectFlushStatus.PENDING:
					eventDispatcher.dispatchEvent(new Event(SharedObjectFlushStatus.PENDING));
					return false;
				case true: 		
					eventDispatcher.dispatchEvent(new Event(Event.COMPLETE));
					_soModified = false;
					return true;	
				case false: 	
					eventDispatcher.dispatchEvent(new Event(ErrorEvent.ERROR));		
					return false;
				default:
					return false;
			}
			
		}
		
		/**
	     * @private
	     */
	    public function addEventListener(type:String, listener:Function, useCapture:Boolean = false, priority:int = 0, useWeakReference:Boolean = false):void {
	        eventDispatcher.addEventListener(type, listener, useCapture, priority, useWeakReference);
	    }
	
	    /**
	     * @private
	     */
	    public function dispatchEvent(event:Event):Boolean {
	        return eventDispatcher.dispatchEvent(event);
	    }
	
	    /**
	     * @private
	     */
	    public function removeEventListener(type:String, listener:Function, useCapture:Boolean = false):void {
	        eventDispatcher.removeEventListener(type, listener, useCapture);
	    }
	
	    /**
	     * @private
	     */
	    public function hasEventListener(type:String):Boolean {
	        return eventDispatcher.hasEventListener(type);
	    }
	    
	    /**
	     * @private
	     */
	    public function willTrigger(type:String):Boolean {
	        return eventDispatcher.willTrigger(type);
	    }
		
		/**
		 * SharedObject name validator
		 * @return Boolean value with name validity
		 */
		public static function validateName(name:String):Boolean{
			for each(var s:String in LocalStore.ILLEGAL_CHARACTERS){
				if(name.indexOf(s) != -1) return false;
			}
			return true;
		} 
		
	}
}